﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;
using M7;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Drawing.Imaging;

namespace C7
{
    public class TcpConnection
    {
        public static bool IsConnected = false;
        public static Thread thrListen = new Thread(new ThreadStart(Listen));
        public static Thread thrRead = new Thread(new ThreadStart(ReadMsg));
        public static Thread thrSend = new Thread(new ThreadStart(Send));

        private static TcpListener listener = new TcpListener(IPAddress.Any, Info.current.Port);

        public static Queue<Msg> SendingQueue = new Queue<Msg>();
        public static Queue<Msg> ReadingQueue = new Queue<Msg>();

        //private static Enum Ack(Msg msg)
        //{
        //    Enum operationType = null;
        //    if (msg.enumMethod is enumBooking)
        //    {
        //        enumBooking method = (enumBooking)msg.enumMethod;
        //        switch (method)
        //        {
        //            case enumBooking.BookingAdd:
        //                {
        //                    operationType = enumAck.AckBookingAdd;
        //                    break;
        //                }
        //            case enumBooking.BookingCancel:
        //                {
        //                    operationType = enumAck.AckBookingCancel;
        //                    break;
        //                }
        //            case enumBooking.BookingDelete:
        //                {
        //                    operationType = enumAck.AckBookingDelete;
        //                    break;
        //                }
        //            case enumBooking.BookingEdit:
        //                {
        //                    operationType = enumAck.AckBookingEdit;
        //                    break;
        //                }
        //        }
        //    }
        //    else if (msg.enumMethod is enumChat)
        //    {
        //        enumChat method = (enumChat)msg.enumMethod;
        //        switch (method)
        //        {
        //            case enumChat.ChatConnect:
        //                {
        //                    operationType = enumAck.AckChatConnect;
        //                    break;
        //                }
        //            case enumChat.ChatDisconnect:
        //                {
        //                    operationType = enumAck.AckChatDisconnect;
        //                    break;
        //                }
        //            case enumChat.ChatSend:
        //                {
        //                    operationType = enumAck.AckChatSend;
        //                    break;
        //                }

        //            case enumChat.ChatReceiveMsg:
        //                {
        //                    operationType = enumAck.AckChatReceiveMsg;
        //                    break;
        //                }
        //        }
        //    }
        //    else if (msg.enumMethod is enumConnection)
        //    {
        //        enumConnection method = (enumConnection)msg.enumMethod;
        //        switch (method)
        //        {
        //            case enumConnection.ConnectionConnect:
        //                {
        //                    operationType = enumAck.AckConnectionConnect;
        //                    break;
        //                }
        //            case enumConnection.ConnectionDisconnect:
        //                {
        //                    operationType = enumAck.AckConnectionDisconnect;
        //                    break;
        //                }
        //        }
        //    }
        //    else if (msg.enumMethod is enumCustomer)
        //    {
        //        enumCustomer method = (enumCustomer)msg.enumMethod;
        //        switch (method)
        //        {
        //            case enumCustomer.CustomerDelete:
        //                {
        //                    operationType = enumAck.AckCustomerDelete;
        //                    break;
        //                }
        //            case enumCustomer.CustomerSignIn:
        //                {
        //                    operationType = enumAck.AckCustomerSignIn;
        //                    break;
        //                }
        //            case enumCustomer.CustomerSignOut:
        //                {
        //                    operationType = enumAck.AckCustomerSignOut;
        //                    break;
        //                }
        //            case enumCustomer.CustomerSignUp:
        //                {
        //                    operationType = enumAck.AckCustomerSignUp;
        //                    break;
        //                }
        //        }
        //    }
        //    else if (msg.enumMethod is enumFavorite)
        //    {
        //        enumFavorite method = (enumFavorite)msg.enumMethod;
        //        switch (method)
        //        {
        //            case enumFavorite.FavoriteAdd:
        //                {
        //                    operationType = enumAck.AckFavoriteAdd;
        //                    break;
        //                }
        //            case enumFavorite.FavoriteDelete:
        //                {
        //                    operationType = enumAck.AckFavoriteDelete;
        //                    break;
        //                }
        //        }
        //    }
        //    else if (msg.enumMethod is enumFeedback)
        //    {
        //        enumFeedback method = (enumFeedback)msg.enumMethod;
        //        switch (method)
        //        {
        //            case enumFeedback.FeedbackAdd:
        //                {
        //                    operationType = enumAck.AckFeedbackAdd;
        //                    break;
        //                }
        //        }
        //    }
        //    else if (msg.enumMethod is enumMenuItem)
        //    {
        //        enumMenuItem method = (enumMenuItem)msg.enumMethod;
        //        switch (method)
        //        {
        //            case enumMenuItem.MenuItemsSearch:
        //                {
        //                    operationType = enumAck.AckMenuItemsSearch;
        //                    break;
        //                }
        //        }
        //    }
        //    else if (msg.enumMethod is enumMenus)
        //    {
        //        enumMenus method = (enumMenus)msg.enumMethod;
        //        switch (method)
        //        {
        //            case enumMenus.MenusSearch:
        //                {
        //                    operationType = enumAck.AckMenusSearch;
        //                    break;
        //                }
        //        }
        //    }
        //    else if (msg.enumMethod is enumOrder)
        //    {
        //        enumOrder method = (enumOrder)msg.enumMethod;
        //        switch (method)
        //        {
        //            case enumOrder.OrderAdd:
        //                {
        //                    operationType = enumAck.AckOrderAdd;
        //                    break;
        //                }
        //        }
        //    }
        //    return operationType;
        //}

        //public static Msg ReturnMsg(Msg rMsg)
        //{
        //    MsgReceivedEvent[rMsg.enumMethod.ToString()].WaitOne();
        //    rMsg = ResultMsg[rMsg.enumMethod.ToString()];
        //    MsgReceivedEvent[rMsg.enumMethod.ToString()] = new AutoResetEvent(false);
        //    ResultMsg[rMsg.enumMethod.ToString()] = null;
        //    return rMsg;
        //}

        public static void Start()
        {
            thrListen.IsBackground = true;
            thrRead.IsBackground = true;
            thrSend.IsBackground = true;
            IsConnected = true;
            Msg SendMsg = new Msg(Properties.Settings.Default.Port, Properties.Settings.Default.TableID);
            SendMsg.obj = Info.current;
            SendMsg.enumMethod = enumConnection.ConnectionConnect;
            SendingQueue.Enqueue(SendMsg);
            listener.Start();
            thrListen.Start();
            thrRead.Start();
            thrSend.Start();
        }
        private static void Listen()
        {
            while (IsConnected)
            {
                if (listener.Pending())
                {
                    TcpClient client = listener.AcceptTcpClient();
                    GetMsg(client);
                }
                else
                {
                    Thread.Sleep(50);
                }
            }
        }
        public static void Stop()
        {
            //TcpConnection.SendingQueue.Clear();
            //Msg SendMsg = new Msg();
            //SendMsg.enumMethod = enumConnection.ConnectionDisconnect;
            //SendingQueue.Enqueue(SendMsg);
            //TcpConnection.thrSend.Resume();
        }

        public static void Send()
        {            
            while (true)
            {
                try
                {
                    if (SendingQueue.Count != 0)
                    {
                        Msg SendMsg = SendingQueue.Dequeue();
                        MemoryStream ms = Serialization.Serialize(SendMsg);
                        byte[] bo = ms.ToArray();
                        int size = bo.Length;
                        List<byte> lstBytes = bo.ToList();
                        lstBytes.InsertRange(0, BitConverter.GetBytes(size).ToList());
                        byte[] b = lstBytes.ToArray();
                        TcpClient client = new TcpClient();
                        client.SendBufferSize = b.Length;
                        client.Connect(Info.ServerIP, Info.serverPort);
                        client.Client.Send(b);
                        client.Close();
                        if (SendMsg.enumMethod is enumAck)
                        {
                            //Don't wait for an Ack
                        }
                    }
                    else
                    {
                        //No Msg to Send
                        Thread.Sleep(100);
                    }
                }
                catch (SocketException)
                {
                    Thread.Sleep(50);
                }
                catch
                {

                }
            }
        }

        private static void GetMsg(TcpClient client)
        {
            byte[] b = new byte[4];
            int read = client.Client.Receive(b);
            int datasize = BitConverter.ToInt32(b, 0);
            byte[] buffer = new byte[datasize];
            read = client.Client.Receive(buffer);
            client.Close();
            MemoryStream ms = new MemoryStream(buffer);
            Msg msg = new Msg(Properties.Settings.Default.Port, Properties.Settings.Default.TableID);
            msg = (Msg)Serialization.DeSerialize(ms);
            ReadingQueue.Enqueue(msg);
        }


        #region ReadingMethods
        private static void ReadMsg()
        {
            while (true)
            {
                if (ReadingQueue.Count != 0)
                {
                    Msg msg = ReadingQueue.Dequeue();
                    if (msg.Start == "~~" && msg.End == "~~")
                    {
                        if (msg.enumMethod is enumAck)
                        {
                            //Ack is received
                        }
                        else if (msg.enumMethod is enumBooking)
                        {
                            ReadBooking(msg);
                        }
                        else if (msg.enumMethod is enumChat)
                        {
                            ReadChat(msg);
                        }
                        else if (msg.enumMethod is enumConnection)
                        {
                            ReadConnection(msg);
                        }
                        else if (msg.enumMethod is enumCustomer)
                        {
                            ReadCustomer(msg);
                        }
                        else if (msg.enumMethod is enumFavorite)
                        {
                            ReadFavorite(msg);
                        }
                        else if (msg.enumMethod is enumFeedback)
                        {
                            ReadFeedback(msg);
                        }
                        else if (msg.enumMethod is enumMenuItem)
                        {
                            ReadMenuItem(msg);
                        }
                        else if (msg.enumMethod is enumMenus)
                        {
                            ReadMenus(msg);
                        }
                        else if (msg.enumMethod is enumOrder)
                        {
                            ReadOrder(msg);
                        }
                        else if (msg.enumMethod is enumPersonalization)
                        {
                            ReadPersonalization(msg);
                        }
                        else if (msg.enumMethod is enumAdminTools)
                        {
                            ReadAdminTools(msg);
                        }
                        else if (msg.enumMethod  is enumMusic)
                        {
                            ReadMusic(msg);
                        }
                        else if (msg.enumMethod is MessageBoxButton)
                        {
                            ReadMessageBox(msg);
                        }
                    }
                    else
                    {
                        //Error Receiving Msg
                    }
                }
                else
                {
                    //No msg Received
                    Thread.Sleep(200);
                }
            }
        }

        private static void ReadMusic(Msg msg)
        {
            enumMusic method = (enumMusic)msg.enumMethod;
            switch (method)
            {
                case enumMusic.Lyrics:
                    {
                        Info.CurrentSong = (NSong)msg.obj;
                        Info.window.Dispatcher.Invoke(new ThreadStart(() =>
                            {
                                Info.window.mtLowerMarquee.Text = Info.CurrentSong.Lyrics;
                            }));
                        break;
                    }
            }
        }

        private static void ReadChat(Msg msg)
        {
            enumChat method = (enumChat)msg.enumMethod;
            switch (method)
            {
                case enumChat.ChatConnect:
                    {
                        break;
                    }
                case enumChat.ChatDisconnect:
                    {
                        break;
                    }
                case enumChat.ChatSend:
                    {
                        break;
                    }
                case enumChat.ChatReceiveMsg:
                    {
                        if (Info.module is ChatModule)
                        {
                            ChatClient chatClient = (ChatClient)msg.obj;
                            (Info.module as ChatModule).tbChat.Dispatcher.Invoke(new ThreadStart(() =>
                                {
                                    var chats = from chat in (Info.module as ChatModule).tbChat.Items.OfType<ChatClient>()
                                                select chat;
                                    List<ChatClient> list = chats.ToList();
                                    list.Add(chatClient);
                                    (Info.module as ChatModule).tbChat.ItemsSource = list;
                                }));
                        }
                        break;
                    }
            }
        }

        private delegate void delCloseAnimation(object sender, MouseButtonEventArgs e);
        private delegate int delAddUser(UIElement uie);

        private static void ReadMessageBox(Msg msg)
        {
            MessageBoxButton method = (MessageBoxButton)msg.enumMethod;
            switch (method)
            {
                case MessageBoxButton.OK:
                    {

                        break;
                    }
                case MessageBoxButton.OKCancel:
                    {
                        Info.window.Dispatcher.Invoke(new ThreadStart(() =>
                        {
                            Info.window.mtUpperMarquee.Text = msg.obj.ToString();
                        }));
                        break;
                    }
                case MessageBoxButton.YesNo:
                    break;
                case MessageBoxButton.YesNoCancel:
                    break;
            }
        }

        private static void ReadConnection(Msg msg)
        {
            enumConnection method = (enumConnection)msg.enumMethod;
            switch (method)
            {
                case enumConnection.ConnectionConnect:
                    {
                        if (!msg.Succeeded)
                        {
                            Properties.Settings.Default.TableID = (int)msg.obj;
                            Properties.Settings.Default.Save();

                            Msg SendMsg = new Msg(Properties.Settings.Default.Port, Properties.Settings.Default.TableID);
                            SendMsg.enumMethod = method;
                            SendMsg.obj = Info.current;
                            SendingQueue.Enqueue(SendMsg);
                        }
                        else
                        {
                            Msg SendMsg = new Msg(Properties.Settings.Default.Port, Properties.Settings.Default.TableID);
                            SendMsg.obj = Info.current;
                            SendMsg.enumMethod = enumConnection.ConnectionConnect;
                            SendingQueue.Enqueue(SendMsg);
                        }
                        break;
                    }
                case enumConnection.ConnectionDisconnect:
                    break;
            }
            
        }

        private static void ReadCustomer(Msg msg)
        {
            enumCustomer method = (enumCustomer)msg.enumMethod;
            switch (method)
            {
                case enumCustomer.CustomerSignUp:
                    {
                        break;
                    }
                case enumCustomer.CustomerSignIn:
                    {
                        if (msg.Succeeded)
                        {
                            NCustomer newCustomer = (NCustomer)msg.obj;
                            Info.current.CustomerID = newCustomer.CustomerID;
                            Info.current.customers.Add(newCustomer);
                            delCloseAnimation del = new delCloseAnimation((Info.module as LoginWindow).spClose_MouseLeftButtonDown);
                            (Info.module as LoginWindow).Dispatcher.Invoke(del, new object[] { Info.module as LoginWindow, null });
                            CurrentUser User = null;
                            BitmapSource newBit = null;
                            IntPtr hBitmap = C7.Properties.Resources.Avatar__1_.GetHbitmap();
                            BitmapSizeOptions sizeOptions = BitmapSizeOptions.FromEmptyOptions();
                            Application.Current.Dispatcher.Invoke(new ThreadStart(() => { 
                                newBit = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, sizeOptions); 
                            }), null);
                            Application.Current.Dispatcher.Invoke(new ThreadStart(() => { User = new CurrentUser(); }), null);
                            Application.Current.Dispatcher.Invoke(new ThreadStart(() => 
                            { 
                                User.tbUserName.Text = newCustomer.Username;
                                User.imgCurrentUser.Source = newBit;
                            }), null);
                            Application.Current.Dispatcher.Invoke(new ThreadStart(() =>
                                {
                                    Info.UsersPanel.Children.Insert(Info.UsersPanel.Children.Count - 1, User);
                                }));
                            Application.Current.Dispatcher.Invoke(new ThreadStart(() =>
                                {
                                    foreach (FrameworkElement i in Info.UsersPanel.Children)
                                    {
                                        if (i == User)
                                            i.Margin = new Thickness(4, 0, 0, 0);
                                        if (i != User && i != Info.window.imgAdd)
                                            i.Margin = new Thickness(4, 0, 0, 24);
                                    }

                                }));
                        }
                        else
                        {
                            MessageBox.Show(msg.obj.ToString(), "Error!", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
                        }
                        break;
                    }
                case enumCustomer.CustomerSignOut:
                    {
                        break;
                    }
                case enumCustomer.CustomerDelete:
                    {
                        break;
                    }
                case enumCustomer.CustomerGetInfo:
                    {
                        NCustomer newCustomer = (NCustomer)msg.obj;
                        Info.UsersPanel.Dispatcher.Invoke(new ThreadStart(() => { }), null); //Set Info in textboxes
                        break;
                    }
            }
        }

        private static void ReadBooking(Msg msg)
        {
            enumBooking method = (enumBooking)msg.enumMethod;
            switch (method)
            {
                case enumBooking.BookingAdd:
                    {
                        break;
                    }
                case enumBooking.BookingCancel:
                    {
                        break;
                    }
                case enumBooking.BookingDelete:
                    {
                        break;
                    }
                case enumBooking.BookingEdit:
                    {
                        break;
                    }
            }
        }

        private static void ReadFavorite(Msg msg)
        {
            enumFavorite method = (enumFavorite)msg.enumMethod;
            switch (method)
            {
                case enumFavorite.FavoriteAdd:
                    {
                        break;
                    }
                case enumFavorite.FavoriteDelete:
                    {
                        break;
                    }
            }
        }

        private static void ReadFeedback(Msg msg)
        {
            enumFeedback method = (enumFeedback)msg.enumMethod;
            switch (method)
            {
                case enumFeedback.FeedbackAdd:
                    {
                        if (msg.Succeeded)
                        {
                            //MessageBox.Show("Thank you for you Fe
                        }
                        break;
                    }
            }
        }

        private static void ReadMenus(Msg msg)
        {
            List<NMenus> nMenusList = new List<NMenus>();
            nMenusList = (List<NMenus>)msg.obj;
            enumMenus method = (enumMenus)msg.enumMethod;
            switch (method)
            {
                case enumMenus.MenusSearch:
                    {
                        if (Info.module is MenuModule)
                        {
                            Menus.MenusList = nMenusList;
                            (Info.module as MenuModule).Dispatcher.Invoke(Menus.del, null);
                        }
                        break;
                    }
            }
        }

        private static void ReadMenuItem(Msg msg)
        {
            List<NMenuItem> nMenuItemsList = new List<NMenuItem>();
            enumMenuItem method = (enumMenuItem)msg.enumMethod;
            nMenuItemsList = (List<NMenuItem>)msg.obj;
            switch (method)
            {
                case enumMenuItem.MenuItemsSearch:
                    {
                        MenuItem.MenuItemsList.AddRange(nMenuItemsList);
                        break;
                    }
            }
        }

        private static void ReadOrder(Msg msg)
        {
            enumOrder method = (enumOrder)msg.enumMethod;
            switch (method)
            {
                case enumOrder.OrderAdd:
                    {
                        if (msg.Succeeded)
                        {
                            MessageBox.Show("Eshta!");
                        }
                        break;
                    }
                case enumOrder.OrderGet:
                    {
                        List<NMenuItem> Items = (List<NMenuItem>)msg.obj;
                        if (Info.module is CheckoutModule)
                        {
                            (Info.module as CheckoutModule).lbMenuItems.Dispatcher.Invoke(new ThreadStart(() =>
                                {
                                    decimal total = 0;
                                    foreach (var item in Items)
                                    {
                                        total += item.Price;
                                    }
                                    Items.Add(new NMenuItem { Name = "Total", Price = total });
                                    (Info.module as CheckoutModule).lbMenuItems.ItemsSource = Items;
                                }));
                        }
                        break;
                    }
            }
        }

        private static void ReadPersonalization(Msg msg)
        {
            enumPersonalization method = (enumPersonalization)msg.enumMethod;
            switch (method)
            {
                case enumPersonalization.GetGenres:
                    {
                        if (Info.module is PersonalizationModule)
                        {
                            PersonalizationClass.lstGenre = (List<string>)msg.obj;
                            if (PersonalizationClass.lstGenre != null)
                            {
                                (Info.module as PersonalizationModule).lbMusicGenre.Dispatcher.Invoke(PersonalizationClass.del, null);
                            }
                        }
                        break;
                    }
                case enumPersonalization.GetTVChannels:
                    {
                        List<string> lstChannels = (List<string>)msg.obj;
                        if (Info.module is PersonalizationModule)
                        {
                            (Info.module as PersonalizationModule).lbTVChannel.Dispatcher.Invoke(new ThreadStart(() =>
                                                {
                                                    (Info.module as PersonalizationModule).lbTVChannel.Items.Clear();
                                                    foreach (var channel in lstChannels)
                                                    {
                                                        (Info.module as PersonalizationModule).lbTVChannel.Items.Add(channel);
                                                    };
                                                })); 
                        }
                        break;
                    }
                case enumPersonalization.GetACTemp:
                    {
                        List<string> lstAC = (List<string>)msg.obj;

                        if (Info.module is PersonalizationModule)
                        {
                            (Info.module as PersonalizationModule).lbACTemp.Dispatcher.Invoke(new ThreadStart(() =>
                                                {
                                                    (Info.module as PersonalizationModule).lbACTemp.Items.Clear();
                                                    foreach (var ac in lstAC)
                                                    {
                                                        (Info.module as PersonalizationModule).lbACTemp.Items.Add(ac);
                                                    };
                                                })); 
                        }
                        break;
                    }
            }
        }

        private static void ReadAdminTools(Msg msg)
        {
            enumAdminTools method = (enumAdminTools)msg.enumMethod;
            switch (method)
            {
                case enumAdminTools.DisableModule:
                    {
                        Dictionary<enumModules, bool> dic = (Dictionary<enumModules, bool>)msg.obj;
                        AdminTools.SetModules(ref dic);
                        break;
                    }
                case enumAdminTools.SignOutCustomer:
                    {
                        break;
                    }
                case enumAdminTools.GetStatus:
                    {
                        Msg SendMsg = new Msg(Properties.Settings.Default.Port, Properties.Settings.Default.TableID);
                        SendMsg.enumMethod = enumAdminTools.GetStatus;
                        SendMsg.obj = Info.current;
                        TcpConnection.SendingQueue.Enqueue(SendMsg);
                        break;
                    }
                case enumAdminTools.LocalConnection:
                    {
                        break;
                    }
                case enumAdminTools.AdminConnection:
                    {
                        
                        break;
                    }
            }
        }
        #endregion
    }
}
